package mx.com.sinformex.simbel.db.dao.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.TransactionException;

import mx.com.sinformex.simbel.db.dao.IAdminDataAccess;
import mx.com.sinformex.simbel.db.eos.DataSource;
import mx.com.sinformex.simbel.db.eos.Group;
import mx.com.sinformex.simbel.db.eos.Report;
import mx.com.sinformex.simbel.db.eos.ReportGroupJoin;
import mx.com.sinformex.simbel.db.eos.ReportParam;
import mx.com.sinformex.simbel.db.eos.User;
import mx.com.sinformex.simbel.utils.ReportSorter;

/**
 * @author Oscar Ivan Hernandez Ventura [ oscar at sinformex dot com dot mx]
 *
 * @version $ Id : AdminDataAccess.java , v 1.0 08/05/2009 angellore $
 */
public class AdminDataAccess implements IAdminDataAccess {

	private final Log log = LogFactory.getLog(getClass());
	@Resource
	private SessionFactory sessionFactory;
	
	public void deleteUser(User user) throws TransactionException {
		
	}

	public User getUser(String username, String password) {
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(User.class).add(Restrictions.eq("username", username));
		return (User) criteria.uniqueResult();
	}

	public void saveUser(User user) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.saveOrUpdate(user);
	}
	
	public void updateUser(User user) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.update(user);
	}	

	@SuppressWarnings("unchecked")
	public List<User> fetchUsers() {
		Session session = sessionFactory.getCurrentSession();
		return session.createCriteria(User.class).list();
	}

	public void deleteDatasource(DataSource ds) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.delete(ds);
	}

	@SuppressWarnings("unchecked")
	public List<DataSource> fetchDatasources() {
		Session session = sessionFactory.getCurrentSession();
		return session.createCriteria(DataSource.class).list();
	}

	public DataSource getDatasource(String name) {
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(DataSource.class).add(Restrictions.eq("name", name));
		return (DataSource) criteria.uniqueResult();
	}

	public void saveDatasource(DataSource ds) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.save(ds);
	}

	public void updateDatasource(DataSource ds) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.update(ds);
	}

	public void deleteGroup(Group group) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.delete(group);		
	}

	@SuppressWarnings("unchecked")
	public List<Group> fetchGroups() {
		Session session = sessionFactory.getCurrentSession();
		List<Group> groups = session.createCriteria(Group.class).list();
		for(Group group : groups) {
			int value = group.getReports().size();
			if(log.isDebugEnabled()) {
				log.debug(String.format("Group %s have %d reports", group.getName(), value));
			}
		}
		return groups;
	}

	public Group getGroup(Integer id) {
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(Group.class).add(Restrictions.eq("groupId", id));
		Group group = (Group) criteria.uniqueResult();
		int value = group.getReports().size();
		if(log.isDebugEnabled()) {
			log.debug(String.format("Group %s have %d reports", group.getName(), value));
		}
		return group;
	}

	public void saveGroup(Group group) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.save(group);	
	}

	public void updateGroup(Group group) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		Transaction tx = session.beginTransaction();
		session.update(group);
		
		/*if(group.getReports() != null) {
			for(Report report : group.getReports()) {
				session.update(report);
			}
		}*/
		tx.commit();
	}

	public void deleteReport(Report report) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.delete(report);
	}

	@SuppressWarnings("unchecked")
	public List<Report> fetchReports() {
		Session session = sessionFactory.getCurrentSession();
		List<Report> list= session.createCriteria(Report.class).list();
		HashSet hashSet = new HashSet(list);
		ArrayList reports = new ArrayList(hashSet);
		Collections.sort(reports, new ReportSorter());
		return reports;
	}

	public Report getReport(Integer id) {
		Session session = sessionFactory.getCurrentSession();
		return (Report) session.createCriteria(Report.class).add(Restrictions.eq("reportId", id)).uniqueResult();
	}

	public void saveReport(Report report) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		session.save(report);
	}

	public void updateReport(Report report) throws TransactionException {
		Session session = sessionFactory.getCurrentSession();
		Transaction tx = session.beginTransaction();

		try {
			session.update(report);
			if(report.getParams() != null) {
				for(ReportParam param : report.getParams()) {
					session.update(param);
				}
			}
			tx.commit();
		} catch(Exception e) {
			tx.rollback();
			tx = null;
		}
	}

	public void addParamToReport(Report report, ReportParam param) {
		Session session = sessionFactory.getCurrentSession();
		param.setReportId(report.getReportId());
		param.setReportParamId(null);
		session.save(param);
	}

	public void deleteParamFromReport(Report report, ReportParam param) {
		Session session = sessionFactory.getCurrentSession();
		session.delete(param);
	}

	public ReportParam getReportParam(Integer id) {
		Session session = sessionFactory.getCurrentSession();
		return (ReportParam) session.createCriteria(ReportParam.class).add(Restrictions.eq("reportParamId", id)).uniqueResult();
	}

	public void addReportGroupJoin(ReportGroupJoin join) {
		Session session = sessionFactory.getCurrentSession();
		session.save(join);
	}

	public void deleteReportGroupJoin(ReportGroupJoin join) {
		Session session = sessionFactory.getCurrentSession();
		session.delete(join);
	}

	public ReportGroupJoin getReportGroupJoin(Integer group, Integer report) {
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(ReportGroupJoin.class).add(Restrictions.and(Restrictions.eq("report", report), Restrictions.eq("group", group)));
		return (ReportGroupJoin) criteria.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public List<ReportGroupJoin> fetchGroupReportJoin() {
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(ReportGroupJoin.class).addOrder(Order.asc("group")).addOrder(Order.asc("report"));
		return criteria.list();
	}

}
